<?php
session_start();

// 数据库连接类
class DatabaseConnection {
    private $host;
    private $username;
    private $password;
    private $database;
    private $port;
    private $connection;
    
    public function __construct($host, $username, $password, $database, $port = 3306) {
        $this->host = $host;
        $this->username = $username;
        $this->password = $password;
        $this->database = $database;
        $this->port = $port;
    }
    
    public function connect() {
        try {
            $dsn = "mysql:host={$this->host};port={$this->port};dbname={$this->database};charset=utf8mb4";
            $options = [
                PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
                PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
                PDO::ATTR_EMULATE_PREPARES => false,
            ];
            
            $this->connection = new PDO($dsn, $this->username, $this->password, $options);
            return true;
        } catch (PDOException $e) {
            return "连接失败: " . $e->getMessage();
        }
    }
    
    public function getTables() {
        if (!$this->connection) return [];
        
        $stmt = $this->connection->query("SHOW TABLES");
        $tables = $stmt->fetchAll(PDO::FETCH_COLUMN);
        return $tables;
    }
    
    public function getTableColumns($tableName) {
        if (!$this->connection) return [];
        
        $stmt = $this->connection->prepare("DESCRIBE `$tableName`");
        $stmt->execute();
        $columns = $stmt->fetchAll();
        
        $result = [];
        foreach ($columns as $col) {
            $result[] = [
                'name' => $col['Field'],
                'type' => $col['Type'],
                'nullable' => $col['Null'] === 'YES',
                'key' => $col['Key'],
                'default' => $col['Default'],
                'extra' => $col['Extra']
            ];
        }
        
        return $result;
    }
    
    public function getConnection() {
        return $this->connection;
    }
    
    public function close() {
        $this->connection = null;
    }
}

// 数据迁移类
class DataMigrator {
    private $sourceDB;
    private $targetDB;
    private $mapping;
    private $batchSize = 100;
    private $totalRecords = 0;
    private $migratedRecords = 0;
    
    public function __construct($sourceDB, $targetDB) {
        $this->sourceDB = $sourceDB;
        $this->targetDB = $targetDB;
    }
    
    public function setMapping($mapping) {
        $this->mapping = $mapping;
    }
    
    public function setBatchSize($size) {
        $this->batchSize = $size;
    }
    
    public function getTotalRecords() {
        return $this->totalRecords;
    }
    
    public function getMigratedRecords() {
        return $this->migratedRecords;
    }
    
    public function migrate($sourceTable, $targetTable) {
        try {
            $sourceConn = $this->sourceDB->getConnection();
            $targetConn = $this->targetDB->getConnection();
            
            // 获取源表总记录数
            $stmt = $sourceConn->query("SELECT COUNT(*) FROM `$sourceTable`");
            $this->totalRecords = $stmt->fetchColumn();
            
            // 准备插入语句
            $targetColumns = [];
            $sourceColumns = [];
            
            foreach ($this->mapping as $map) {
                if ($map['source'] === '') continue;
                
                $targetColumns[] = "`{$map['target']}`";
                
                if ($map['transform'] === 'direct') {
                    $sourceColumns[] = "`{$map['source']}`";
                } elseif ($map['transform'] === 'uppercase') {
                    $sourceColumns[] = "UPPER(`{$map['source']}`) AS `{$map['source']}`";
                } elseif ($map['transform'] === 'lowercase') {
                    $sourceColumns[] = "LOWER(`{$map['source']}`) AS `{$map['source']}`";
                } elseif ($map['transform'] === 'concat') {
                    $sourceColumns[] = "CONCAT(`{$map['source']}`, '{$map['transform_param']}') AS `{$map['source']}`";
                } elseif ($map['transform'] === 'date_format') {
                    $sourceColumns[] = "DATE_FORMAT(`{$map['source']}`, '{$map['transform_param']}') AS `{$map['source']}`";
                } elseif ($map['transform'] === 'constant') {
                    $sourceColumns[] = "'{$map['transform_param']}' AS `{$map['source']}`";
                }
            }
            
            $columnsStr = implode(', ', $targetColumns);
            $selectStr = implode(', ', $sourceColumns);
            
            // 分页迁移
            $offset = 0;
            $this->migratedRecords = 0;
            
            while ($offset < $this->totalRecords) {
                $sourceStmt = $sourceConn->prepare(
                    "SELECT $selectStr FROM `$sourceTable` LIMIT :limit OFFSET :offset"
                );
                
                $sourceStmt->bindValue(':limit', $this->batchSize, PDO::PARAM_INT);
                $sourceStmt->bindValue(':offset', $offset, PDO::PARAM_INT);
                $sourceStmt->execute();
                
                $rows = $sourceStmt->fetchAll();
                
                if (empty($rows)) break;
                
                // 构建插入语句
                $placeholders = rtrim(str_repeat('?,', count($targetColumns)), ',');
                $insertSql = "INSERT INTO `$targetTable` ($columnsStr) VALUES ($placeholders)";
                $targetStmt = $targetConn->prepare($insertSql);
                
                // 插入数据
                foreach ($rows as $row) {
                    $values = [];
                    foreach ($this->mapping as $map) {
                        if ($map['source'] === '') continue;
                        $values[] = $row[$map['source']] ?? null;
                    }
                    $targetStmt->execute($values);
                }
                
                $offset += $this->batchSize;
                $this->migratedRecords += count($rows);
            }
            
            return true;
        } catch (PDOException $e) {
            return "迁移失败: " . $e->getMessage();
        }
    }
}

// 处理表单提交
$error = '';
$success = '';
$sourceTables = [];
$targetTables = [];
$sourceColumns = [];
$targetColumns = [];
$mapping = [];

// 默认数据库配置
$defaultConfig = [
    'source_host' => 'localhost',
    'source_port' => 3306,
    'source_user' => 'root',
    'source_pass' => '',
    'source_db' => '',
    'target_host' => 'localhost',
    'target_port' => 3306,
    'target_user' => 'root',
    'target_pass' => '',
    'target_db' => ''
];

// 从session恢复数据
if (isset($_SESSION['source_db'])) {
    $defaultConfig = array_merge($defaultConfig, $_SESSION['source_db'], $_SESSION['target_db']);
    $sourceTables = $_SESSION['source_tables'] ?? [];
    $targetTables = $_SESSION['target_tables'] ?? [];
    $sourceColumns = $_SESSION['source_columns'] ?? [];
    $targetColumns = $_SESSION['target_columns'] ?? [];
    $mapping = $_SESSION['mapping'] ?? [];
}

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    // 数据库连接
    if (isset($_POST['connect'])) {
        try {
            // 源数据库连接
            $sourceDB = new DatabaseConnection(
                $_POST['source_host'],
                $_POST['source_user'],
                $_POST['source_pass'],
                $_POST['source_db'],
                $_POST['source_port']
            );
            
            $connectResult = $sourceDB->connect();
            if ($connectResult !== true) {
                $error = "源数据库: $connectResult";
            } else {
                $sourceTables = $sourceDB->getTables();
                $_SESSION['source_db'] = [
                    'host' => $_POST['source_host'],
                    'user' => $_POST['source_user'],
                    'pass' => $_POST['source_pass'],
                    'db' => $_POST['source_db'],
                    'port' => $_POST['source_port']
                ];
                $_SESSION['source_tables'] = $sourceTables;
            }
            
            // 目标数据库连接
            $targetDB = new DatabaseConnection(
                $_POST['target_host'],
                $_POST['target_user'],
                $_POST['target_pass'],
                $_POST['target_db'],
                $_POST['target_port']
            );
            
            $connectResult = $targetDB->connect();
            if ($connectResult !== true) {
                $error = $error ? $error . "<br>目标数据库: $connectResult" : "目标数据库: $connectResult";
            } else {
                $targetTables = $targetDB->getTables();
                $_SESSION['target_db'] = [
                    'host' => $_POST['target_host'],
                    'user' => $_POST['target_user'],
                    'pass' => $_POST['target_pass'],
                    'db' => $_POST['target_db'],
                    'port' => $_POST['target_port']
                ];
                $_SESSION['target_tables'] = $targetTables;
            }
        } catch (Exception $e) {
            $error = "连接错误: " . $e->getMessage();
        }
    }
    
    // 表选择
    if (isset($_POST['select_tables'])) {
        try {
            $sourceDB = new DatabaseConnection(
                $_SESSION['source_db']['host'],
                $_SESSION['source_db']['user'],
                $_SESSION['source_db']['pass'],
                $_SESSION['source_db']['db'],
                $_SESSION['source_db']['port']
            );
            $sourceDB->connect();
            
            $targetDB = new DatabaseConnection(
                $_SESSION['target_db']['host'],
                $_SESSION['target_db']['user'],
                $_SESSION['target_db']['pass'],
                $_SESSION['target_db']['db'],
                $_SESSION['target_db']['port']
            );
            $targetDB->connect();
            
            $sourceTable = $_POST['source_table'];
            $targetTable = $_POST['target_table'];
            
            $sourceColumns = $sourceDB->getTableColumns($sourceTable);
            $targetColumns = $targetDB->getTableColumns($targetTable);
            
            $_SESSION['source_table'] = $sourceTable;
            $_SESSION['target_table'] = $targetTable;
            $_SESSION['source_columns'] = $sourceColumns;
            $_SESSION['target_columns'] = $targetColumns;
            
            // 尝试自动映射
            $mapping = [];
            foreach ($targetColumns as $targetCol) {
                $found = false;
                foreach ($sourceColumns as $sourceCol) {
                    if (strtolower($targetCol['name']) === strtolower($sourceCol['name'])) {
                        $mapping[] = [
                            'source' => $sourceCol['name'],
                            'target' => $targetCol['name'],
                            'transform' => 'direct',
                            'transform_param' => ''
                        ];
                        $found = true;
                        break;
                    }
                }
                
                if (!$found) {
                    $mapping[] = [
                        'source' => '',
                        'target' => $targetCol['name'],
                        'transform' => 'direct',
                        'transform_param' => ''
                    ];
                }
            }
            
            $_SESSION['mapping'] = $mapping;
        } catch (Exception $e) {
            $error = "表选择错误: " . $e->getMessage();
        }
    }
    
    // 更新映射
    if (isset($_POST['update_mapping'])) {
        $mapping = [];
        if (isset($_POST['target'])) {
            foreach ($_POST['target'] as $index => $targetCol) {
                $sourceCol = $_POST['source'][$index] ?? '';
                $transform = $_POST['transform'][$index] ?? 'direct';
                $transformParam = $_POST['transform_param'][$index] ?? '';
                
                $mapping[] = [
                    'source' => $sourceCol,
                    'target' => $targetCol,
                    'transform' => $transform,
                    'transform_param' => $transformParam
                ];
            }
        }
        
        $_SESSION['mapping'] = $mapping;
        $success = "字段映射配置已更新！";
    }
    
    // 执行迁移
    if (isset($_POST['migrate'])) {
        try {
            $sourceDB = new DatabaseConnection(
                $_SESSION['source_db']['host'],
                $_SESSION['source_db']['user'],
                $_SESSION['source_db']['pass'],
                $_SESSION['source_db']['db'],
                $_SESSION['source_db']['port']
            );
            $sourceDB->connect();
            
            $targetDB = new DatabaseConnection(
                $_SESSION['target_db']['host'],
                $_SESSION['target_db']['user'],
                $_SESSION['target_db']['pass'],
                $_SESSION['target_db']['db'],
                $_SESSION['target_db']['port']
            );
            $targetDB->connect();
            
            $migrator = new DataMigrator($sourceDB, $targetDB);
            $migrator->setMapping($_SESSION['mapping']);
            
            $batchSize = isset($_POST['batch_size']) ? (int)$_POST['batch_size'] : 100;
            $migrator->setBatchSize($batchSize);
            
            $result = $migrator->migrate(
                $_SESSION['source_table'],
                $_SESSION['target_table']
            );
            
            if ($result === true) {
                $success = "数据迁移成功! 迁移记录: " . 
                          $migrator->getMigratedRecords() . " / " . 
                          $migrator->getTotalRecords();
            } else {
                $error = $result;
            }
        } catch (Exception $e) {
            $error = "迁移错误: " . $e->getMessage();
        }
    }
    
    // 重置会话
    if (isset($_POST['reset'])) {
        session_destroy();
        session_start();
        $sourceTables = [];
        $targetTables = [];
        $sourceColumns = [];
        $targetColumns = [];
        $mapping = [];
        $success = "会话已重置，可以开始新的迁移";
    }
}

// 获取参数占位符文本
function getParamPlaceholder($type) {
    switch($type) {
        case 'concat': return '输入要拼接的字符串';
        case 'date_format': return '如: %Y-%m-%d';
        case 'constant': return '输入常量值';
        default: return '';
    }
}
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>数据库表数据迁移工具</title>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <style>
        * {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
        }
        
        body {
            background: linear-gradient(135deg, #f5f7fa 0%, #e4edf5 100%);
            color: #333;
            line-height: 1.6;
            padding: 20px;
            min-height: 100vh;
        }
        
        .container {
            max-width: 1200px;
            margin: 0 auto;
            background: white;
            border-radius: 15px;
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
            overflow: hidden;
        }
        
        header {
            background: linear-gradient(135deg, #6a11cb 0%, #2575fc 100%);
            color: white;
            padding: 25px;
            text-align: center;
            position: relative;
        }
        
        .header-content {
            position: relative;
            z-index: 2;
        }
        
        h1 {
            font-size: 2.5rem;
            margin-bottom: 10px;
            font-weight: 700;
        }
        
        .subtitle {
            font-size: 1.2rem;
            opacity: 0.9;
            max-width: 800px;
            margin: 0 auto;
            font-weight: 300;
        }
        
        .header-icon {
            position: absolute;
            right: 30px;
            top: 30px;
            font-size: 3rem;
            opacity: 0.2;
        }
        
        .main-content {
            padding: 30px;
        }
        
        .section {
            background: white;
            border-radius: 12px;
            box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05);
            padding: 25px;
            margin-bottom: 30px;
            border: 1px solid #eaeaea;
        }
        
        .section-title {
            font-size: 1.6rem;
            color: #2c3e50;
            margin-bottom: 25px;
            padding-bottom: 15px;
            border-bottom: 3px solid #3498db;
            display: flex;
            align-items: center;
        }
        
        .section-title i {
            margin-right: 12px;
            color: #3498db;
        }
        
        .form-row {
            display: flex;
            flex-wrap: wrap;
            margin: 0 -12px 20px;
        }
        
        .form-group {
            flex: 1 0 250px;
            padding: 0 12px;
            margin-bottom: 20px;
        }
        
        label {
            display: block;
            margin-bottom: 10px;
            font-weight: 600;
            color: #2c3e50;
            font-size: 1.05rem;
        }
        
        input[type="text"],
        input[type="password"],
        input[type="number"],
        select,
        textarea {
            width: 100%;
            padding: 14px;
            border: 1px solid #ddd;
            border-radius: 8px;
            font-size: 16px;
            transition: all 0.3s;
            background: #fafbfc;
        }
        
        input:focus, select:focus, textarea:focus {
            outline: none;
            border-color: #3498db;
            box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.2);
            background: white;
        }
        
        .btn {
            display: inline-flex;
            align-items: center;
            justify-content: center;
            padding: 14px 28px;
            background: #3498db;
            color: white;
            border: none;
            border-radius: 8px;
            cursor: pointer;
            font-size: 16px;
            font-weight: 600;
            text-align: center;
            transition: all 0.3s ease;
            gap: 8px;
        }
        
        .btn i {
            font-size: 1.1em;
        }
        
        .btn:hover {
            transform: translateY(-3px);
            box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
        }
        
        .btn:active {
            transform: translateY(-1px);
        }
        
        .btn-primary {
            background: linear-gradient(135deg, #3498db 0%, #2c80c7 100%);
        }
        
        .btn-success {
            background: linear-gradient(135deg, #27ae60 0%, #219653 100%);
        }
        
        .btn-danger {
            background: linear-gradient(135deg, #e74c3c 0%, #c0392b 100%);
        }
        
        .btn-info {
            background: linear-gradient(135deg, #00c9ff 0%, #0088ff 100%);
        }
        
        .btn-lg {
            padding: 16px 32px;
            font-size: 18px;
        }
        
        .btn-center {
            display: flex;
            margin: 25px auto;
        }
        
        .btn-full {
            width: 100%;
        }
        
        .mapping-container {
            overflow-x: auto;
            margin-top: 20px;
            border: 1px solid #eee;
            border-radius: 8px;
            padding: 15px;
            background: #fafbfc;
        }
        
        table {
            width: 100%;
            border-collapse: separate;
            border-spacing: 0;
            margin: 10px 0;
        }
        
        th, td {
            padding: 14px 16px;
            text-align: left;
            border-bottom: 1px solid #eee;
        }
        
        th {
            background-color: #f1f8ff;
            font-weight: 700;
            color: #2c3e50;
        }
        
        tr:hover {
            background-color: #f8fafd;
        }
        
        .status {
            padding: 18px;
            border-radius: 8px;
            margin: 25px 0;
            text-align: center;
            font-size: 1.1rem;
        }
        
        .error {
            background-color: #ffebee;
            color: #f44336;
            border: 1px solid #ffcdd2;
        }
        
        .success {
            background-color: #e8f5e9;
            color: #4caf50;
            border: 1px solid #c8e6c9;
        }
        
        .db-card {
            background: #f8fafd;
            border-left: 4px solid #3498db;
            padding: 20px;
            margin-bottom: 20px;
            border-radius: 8px;
            box-shadow: 0 3px 10px rgba(0, 0, 0, 0.03);
        }
        
        .card-title {
            font-weight: 700;
            margin-bottom: 15px;
            color: #2c3e50;
            font-size: 1.2rem;
            display: flex;
            align-items: center;
            gap: 10px;
        }
        
        .transform-param {
            display: none;
            width: 100%;
        }
        
        .progress-container {
            height: 22px;
            background-color: #e0e7ff;
            border-radius: 11px;
            margin: 25px 0;
            overflow: hidden;
            box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1);
        }
        
        .progress-bar {
            height: 100%;
            background: linear-gradient(90deg, #6a11cb, #2575fc);
            border-radius: 11px;
            width: 0%;
            transition: width 0.7s ease;
            display: flex;
            align-items: center;
            justify-content: flex-end;
            padding-right: 10px;
            color: white;
            font-weight: bold;
            font-size: 0.85rem;
        }
        
        .flex-container {
            display: flex;
            gap: 25px;
        }
        
        .flex-half {
            flex: 1;
        }
        
        .step-container {
            display: flex;
            justify-content: space-between;
            margin: 30px 0;
            position: relative;
        }
        
        .step-container::before {
            content: '';
            position: absolute;
            top: 20px;
            left: 0;
            right: 0;
            height: 3px;
            background: #e0e0e0;
            z-index: 1;
        }
        
        .step {
            position: relative;
            z-index: 2;
            text-align: center;
            flex: 1;
        }
        
        .step-icon {
            width: 40px;
            height: 40px;
            background: #e0e0e0;
            border-radius: 50%;
            display: flex;
            align-items: center;
            justify-content: center;
            margin: 0 auto 10px;
            color: white;
            font-weight: bold;
            font-size: 1.2rem;
            transition: all 0.3s;
        }
        
        .step.active .step-icon {
            background: #3498db;
            transform: scale(1.1);
        }
        
        .step.completed .step-icon {
            background: #27ae60;
        }
        
        .step-label {
            font-weight: 600;
            color: #777;
        }
        
        .step.active .step-label {
            color: #3498db;
        }
        
        .step.completed .step-label {
            color: #27ae60;
        }
        
        .summary-card {
            background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
            border-radius: 10px;
            padding: 20px;
            margin-bottom: 25px;
            border: 1px solid #dee2e6;
        }
        
        .summary-card h3 {
            margin-bottom: 15px;
            color: #2c3e50;
            border-bottom: 2px solid #3498db;
            padding-bottom: 10px;
        }
        
        .summary-row {
            display: flex;
            margin-bottom: 10px;
        }
        
        .summary-label {
            font-weight: 600;
            color: #495057;
            min-width: 150px;
        }
        
        .summary-value {
            color: #212529;
        }
        
        .mapping-hint {
            background: #e3f2fd;
            border-left: 4px solid #2196f3;
            padding: 15px;
            border-radius: 4px;
            margin-bottom: 20px;
            font-size: 0.95rem;
        }
        
        .btn-group {
            display: flex;
            gap: 15px;
            margin-top: 20px;
        }
        
        .type-tag {
            display: inline-block;
            padding: 2px 8px;
            border-radius: 4px;
            background: #e3f2fd;
            color: #1976d2;
            font-size: 0.85rem;
            margin-left: 8px;
        }
        
        @media (max-width: 768px) {
            .flex-container {
                flex-direction: column;
            }
            
            .form-group {
                flex: 1 0 100%;
            }
            
            .step-container {
                flex-wrap: wrap;
            }
            
            .step {
                flex: 0 0 33%;
                margin-bottom: 20px;
            }
            
            h1 {
                font-size: 2rem;
            }
            
            .btn-group {
                flex-direction: column;
            }
        }
    </style>
</head>
<body>
    <div class="container">
        <header>
            <div class="header-content">
                <h1><i class="fas fa-database"></i> 数据库表数据迁移工具</h1>
                <p class="subtitle">在不同结构数据库表之间迁移数据，支持字段映射和转换功能</p>
            </div>
            <div class="header-icon">
                <i class="fas fa-exchange-alt"></i>
            </div>
        </header>
        
        <div class="main-content">
            <!-- 步骤指示器 -->
            <div class="step-container">
                <div class="step <?= !empty($sourceTables) ? 'completed' : 'active' ?>">
                    <div class="step-icon">1</div>
                    <div class="step-label">数据库连接</div>
                </div>
                <div class="step <?= !empty($sourceColumns) ? 'completed' : (!empty($sourceTables) ? 'active' : '') ?>">
                    <div class="step-icon">2</div>
                    <div class="step-label">选择数据表</div>
                </div>
                <div class="step <?= !empty($mapping) ? 'completed' : (!empty($sourceColumns) ? 'active' : '') ?>">
                    <div class="step-icon">3</div>
                    <div class="step-label">字段映射</div>
                </div>
                <div class="step <?= isset($_POST['migrate']) ? 'active' : '' ?>">
                    <div class="step-icon">4</div>
                    <div class="step-label">执行迁移</div>
                </div>
            </div>
            
            <?php if ($error): ?>
                <div class="status error">
                    <i class="fas fa-exclamation-circle"></i> <?php echo $error; ?>
                </div>
            <?php endif; ?>
            
            <?php if ($success): ?>
                <div class="status success">
                    <i class="fas fa-check-circle"></i> <?php echo $success; ?>
                </div>
            <?php endif; ?>
            
            <!-- 数据库连接配置 -->
            <div class="section">
                <h2 class="section-title"><i class="fas fa-plug"></i> 数据库连接配置</h2>
                <form method="post">
                    <div class="flex-container">
                        <div class="flex-half">
                            <div class="db-card">
                                <div class="card-title"><i class="fas fa-database"></i> 源数据库</div>
                                <div class="form-group">
                                    <label><i class="fas fa-server"></i> 主机</label>
                                    <input type="text" name="source_host" value="<?= $defaultConfig['source_host'] ?>" required>
                                </div>
                                <div class="form-group">
                                    <label><i class="fas fa-ethernet"></i> 端口</label>
                                    <input type="number" name="source_port" value="<?= $defaultConfig['source_port'] ?>" required>
                                </div>
                                <div class="form-group">
                                    <label><i class="fas fa-user"></i> 用户名</label>
                                    <input type="text" name="source_user" value="<?= $defaultConfig['source_user'] ?>" required>
                                </div>
                                <div class="form-group">
                                    <label><i class="fas fa-key"></i> 密码</label>
                                    <input type="password" name="source_pass" value="<?= $defaultConfig['source_pass'] ?>">
                                </div>
                                <div class="form-group">
                                    <label><i class="fas fa-database"></i> 数据库名</label>
                                    <input type="text" name="source_db" value="<?= $defaultConfig['source_db'] ?>" required>
                                </div>
                            </div>
                        </div>
                        
                        <div class="flex-half">
                            <div class="db-card">
                                <div class="card-title"><i class="fas fa-database"></i> 目标数据库</div>
                                <div class="form-group">
                                    <label><i class="fas fa-server"></i> 主机</label>
                                    <input type="text" name="target_host" value="<?= $defaultConfig['target_host'] ?>" required>
                                </div>
                                <div class="form-group">
                                    <label><i class="fas fa-ethernet"></i> 端口</label>
                                    <input type="number" name="target_port" value="<?= $defaultConfig['target_port'] ?>" required>
                                </div>
                                <div class="form-group">
                                    <label><i class="fas fa-user"></i> 用户名</label>
                                    <input type="text" name="target_user" value="<?= $defaultConfig['target_user'] ?>" required>
                                </div>
                                <div class="form-group">
                                    <label><i class="fas fa-key"></i> 密码</label>
                                    <input type="password" name="target_pass" value="<?= $defaultConfig['target_pass'] ?>">
                                </div>
                                <div class="form-group">
                                    <label><i class="fas fa-database"></i> 数据库名</label>
                                    <input type="text" name="target_db" value="<?= $defaultConfig['target_db'] ?>" required>
                                </div>
                            </div>
                        </div>
                    </div>
                    
                    <div class="btn-group">
                        <button type="submit" name="connect" class="btn btn-primary">
                            <i class="fas fa-link"></i> 连接数据库
                        </button>
                        <button type="submit" name="reset" class="btn btn-danger">
                            <i class="fas fa-redo"></i> 重置
                        </button>
                    </div>
                </form>
            </div>
            
            <!-- 表选择 -->
            <?php if (!empty($sourceTables) && !empty($targetTables)): ?>
            <div class="section">
                <h2 class="section-title"><i class="fas fa-table"></i> 选择数据表</h2>
                <form method="post">
                    <div class="flex-container">
                        <div class="flex-half">
                            <div class="form-group">
                                <label><i class="fas fa-table"></i> 源数据库表</label>
                                <select name="source_table" id="source-table" required>
                                    <option value="">-- 选择源表 --</option>
                                    <?php foreach ($sourceTables as $table): ?>
                                    <option value="<?= $table ?>" <?= (isset($_SESSION['source_table']) && $_SESSION['source_table'] === $table) ? 'selected' : '' ?>>
                                        <?= $table ?>
                                    </option>
                                    <?php endforeach; ?>
                                </select>
                            </div>
                        </div>
                        
                        <div class="flex-half">
                            <div class="form-group">
                                <label><i class="fas fa-table"></i> 目标数据库表</label>
                                <select name="target_table" id="target-table" required>
                                    <option value="">-- 选择目标表 --</option>
                                    <?php foreach ($targetTables as $table): ?>
                                    <option value="<?= $table ?>" <?= (isset($_SESSION['target_table']) && $_SESSION['target_table'] === $table) ? 'selected' : '' ?>>
                                        <?= $table ?>
                                    </option>
                                    <?php endforeach; ?>
                                </select>
                            </div>
                        </div>
                    </div>
                    
                    <button type="submit" name="select_tables" class="btn btn-primary btn-center">
                        <i class="fas fa-arrow-right"></i> 加载表字段
                    </button>
                </form>
            </div>
            <?php endif; ?>
            
            <!-- 字段映射 -->
            <?php if (!empty($sourceColumns) && !empty($targetColumns)): ?>
            <div class="section">
                <h2 class="section-title"><i class="fas fa-map-signs"></i> 字段映射与转换</h2>
                
                <div class="mapping-hint">
                    <i class="fas fa-info-circle"></i> 
                    请为每个目标字段选择一个源字段并设置转换规则。未映射的字段将保持为空。
                </div>
                
                <form method="post" id="mapping-form">
                    <div class="mapping-container">
                        <table>
                            <thead>
                                <tr>
                                    <th>目标表字段 <span class="type-tag">类型</span></th>
                                    <th>源表字段 <span class="type-tag">类型</span></th>
                                    <th>转换方式</th>
                                    <th>转换参数</th>
                                </tr>
                            </thead>
                            <tbody>
                                <?php foreach ($mapping as $index => $map): 
                                    $targetCol = array_filter($targetColumns, function($col) use ($map) {
                                        return $col['name'] === $map['target'];
                                    });
                                    $targetCol = reset($targetCol);
                                ?>
                                <tr>
                                    <td>
                                        <input type="text" name="target[]" value="<?= $map['target'] ?>" readonly>
                                        <span class="type-tag"><?= $targetCol['type'] ?? '' ?></span>
                                    </td>
                                    <td>
                                        <select name="source[]" class="source-field">
                                            <option value="">-- 不映射 --</option>
                                            <?php foreach ($sourceColumns as $col): ?>
                                            <option value="<?= $col['name'] ?>" 
                                                <?= ($map['source'] === $col['name']) ? 'selected' : '' ?>
                                                data-type="<?= $col['type'] ?>">
                                                <?= $col['name'] ?> 
                                                <span class="type-tag"><?= $col['type'] ?></span>
                                            </option>
                                            <?php endforeach; ?>
                                        </select>
                                    </td>
                                    <td>
                                        <select name="transform[]" class="transform-select" data-index="<?= $index ?>">
                                            <option value="direct" <?= ($map['transform'] === 'direct') ? 'selected' : '' ?>>直接复制</option>
                                            <option value="uppercase" <?= ($map['transform'] === 'uppercase') ? 'selected' : '' ?>>转为大写</option>
                                            <option value="lowercase" <?= ($map['transform'] === 'lowercase') ? 'selected' : '' ?>>转为小写</option>
                                            <option value="concat" <?= ($map['transform'] === 'concat') ? 'selected' : '' ?>>字符串拼接</option>
                                            <option value="date_format" <?= ($map['transform'] === 'date_format') ? 'selected' : '' ?>>日期格式化</option>
                                            <option value="constant" <?= ($map['transform'] === 'constant') ? 'selected' : '' ?>>常量值</option>
                                        </select>
                                    </td>
                                    <td>
                                        <input type="text" name="transform_param[]" 
                                            class="transform-param" 
                                            id="param-<?= $index ?>"
                                            value="<?= $map['transform_param'] ?? '' ?>"
                                            placeholder="<?= getParamPlaceholder($map['transform']) ?>">
                                    </td>
                                </tr>
                                <?php endforeach; ?>
                            </tbody>
                        </table>
                    </div>
                    
                    <div class="btn-group">
                        <button type="submit" name="update_mapping" class="btn btn-primary">
                            <i class="fas fa-save"></i> 保存映射配置
                        </button>
                        <button type="button" id="auto-match" class="btn btn-info">
                            <i class="fas fa-magic"></i> 智能匹配
                        </button>
                    </div>
                </form>
            </div>
            <?php endif; ?>
            
            <!-- 迁移执行 -->
            <?php if (!empty($mapping)): ?>
            <div class="section">
                <h2 class="section-title"><i class="fas fa-truck-loading"></i> 执行数据迁移</h2>
                
                <div class="summary-card">
                    <h3><i class="fas fa-clipboard-list"></i> 迁移摘要</h3>
                    <div class="summary-row">
                        <div class="summary-label">源表:</div>
                        <div class="summary-value"><?= $_SESSION['source_table'] ?? '' ?></div>
                    </div>
                    <div class="summary-row">
                        <div class="summary-label">目标表:</div>
                        <div class="summary-value"><?= $_SESSION['target_table'] ?? '' ?></div>
                    </div>
                    <div class="summary-row">
                        <div class="summary-label">字段映射:</div>
                        <div class="summary-value"><?= count($mapping) ?> 个字段已配置</div>
                    </div>
                    <div class="summary-row">
                        <div class="summary-label">映射状态:</div>
                        <div class="summary-value">
                            <?php 
                                $mappedCount = 0;
                                foreach ($mapping as $map) {
                                    if ($map['source'] !== '') $mappedCount++;
                                }
                                echo "$mappedCount 个字段已映射，".(count($mapping)-$mappedCount)." 个字段未映射";
                            ?>
                        </div>
                    </div>
                </div>
                
                <form method="post">
                    <div class="form-group">
                        <label><i class="fas fa-layer-group"></i> 每批迁移记录数</label>
                        <input type="number" name="batch_size" value="100" min="10" max="1000">
                    </div>
                    
                    <button type="submit" name="migrate" id="start-migration" class="btn btn-success btn-lg btn-center">
                        <i class="fas fa-play"></i> 开始数据迁移
                    </button>
                </form>
            </div>
            <?php endif; ?>
        </div>
    </div>

    <script>
        $(document).ready(function() {
            // 根据选择的转换方式显示/隐藏参数输入框
            $('.transform-select').each(function() {
                const index = $(this).data('index');
                const transformType = $(this).val();
                const paramInput = $('#param-' + index);
                
                if (transformType === 'concat' || transformType === 'date_format' || transformType === 'constant') {
                    paramInput.show();
                    paramInput.attr('placeholder', getParamPlaceholder(transformType));
                } else {
                    paramInput.hide();
                }
            });
            
            // 监听转换方式变化
            $('.transform-select').change(function() {
                const index = $(this).data('index');
                const transformType = $(this).val();
                const paramInput = $('#param-' + index);
                
                if (transformType === 'concat' || transformType === 'date_format' || transformType === 'constant') {
                    paramInput.show();
                    paramInput.attr('placeholder', getParamPlaceholder(transformType));
                } else {
                    paramInput.hide();
                }
            });
            
            // 获取参数占位符文本
            function getParamPlaceholder(type) {
                switch(type) {
                    case 'concat': return '输入要拼接的字符串';
                    case 'date_format': return '如: %Y-%m-%d';
                    case 'constant': return '输入常量值';
                    default: return '';
                }
            }
            
            // 智能匹配按钮
            $('#auto-match').click(function() {
                $('.source-field').each(function() {
                    const targetName = $(this).closest('tr').find('input[name="target[]"]').val().toLowerCase();
                    let found = false;
                    
                    $(this).find('option').each(function() {
                        const sourceName = $(this).val().toLowerCase();
                        if (sourceName === targetName) {
                            $(this).prop('selected', true);
                            found = true;
                            return false; // break loop
                        }
                    });
                    
                    if (!found) {
                        $(this).val('');
                    }
                });
                
                // 显示成功提示
                showNotification('智能匹配完成！系统已自动匹配名称相同的字段。', 'success');
            });
            
            // 迁移按钮点击事件
            $('#start-migration').click(function() {
                const progressBar = $('<div class="progress-container">')
                    .append('<div class="progress-bar" id="migration-progress">0%</div>');
                
                $(this).before(progressBar);
                
                // 模拟进度更新
                let width = 0;
                const interval = setInterval(function() {
                    if (width >= 100) {
                        clearInterval(interval);
                    } else {
                        width += 2;
                        $('#migration-progress')
                            .css('width', width + '%')
                            .text(width + '%');
                    }
                }, 50);
            });
            
            // 显示通知
            function showNotification(message, type) {
                const notification = $('<div class="status">')
                    .addClass(type === 'error' ? 'error' : 'success')
                    .html('<i class="fas ' + (type === 'error' ? 'fa-exclamation-circle' : 'fa-check-circle') + '"></i> ' + message);
                
                $('.main-content').prepend(notification);
                
                // 5秒后自动消失
                setTimeout(function() {
                    notification.fadeOut(500, function() {
                        $(this).remove();
                    });
                }, 5000);
            }
            
            // 字段类型高亮
            $('.source-field').change(function() {
                const selectedOption = $(this).find('option:selected');
                const typeTag = selectedOption.find('.type-tag').text();
                
                if (typeTag) {
                    $(this).next('.type-tag').remove();
                    $(this).after('<span class="type-tag">' + typeTag + '</span>');
                }
            });
            
            // 初始化字段类型显示
            $('.source-field').each(function() {
                const selectedOption = $(this).find('option:selected');
                const typeTag = selectedOption.find('.type-tag').text();
                
                if (typeTag) {
                    $(this).after('<span class="type-tag">' + typeTag + '</span>');
                }
            });
        });
    </script>
</body>
</html>